let scrollBarWidth;
export const getScrollBarWidth = () => {
    if ( scrollBarWidth !== undefined ) return scrollBarWidth;

    const outer = document.createElement( 'div' );
    outer.className = 'g-scrollbar__wrap';
    outer.style.visibility = 'hidden';
    outer.style.width = '100px';
    outer.style.position = 'absolute';
    outer.style.top = '-9999px';
    document.body.appendChild( outer );

    const widthNoScroll = outer.offsetWidth;
    outer.style.overflow = 'scroll';

    const inner = document.createElement( 'div' );
    inner.style.width = '100%';
    outer.appendChild( inner );

    const widthWithScroll = inner.offsetWidth;
    outer.parentNode.removeChild( outer );

    return widthNoScroll - widthWithScroll;
};

const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
const MOZ_HACK_REGEXP = /^moz([A-Z])/;

const trim = function ( string ) {
    return ( string || '' ).replace( /^[\s\uFEFF]+|[\s\uFEFF]+$/g, '' );
};

const camelCase = function ( name ) {
    return name.replace( SPECIAL_CHARS_REGEXP, function ( _, separator, letter, offset ) {
        return offset ? letter.toUpperCase() : letter;
    } ).replace( MOZ_HACK_REGEXP, 'Moz$1' );
};

export const getSize = ( element ) => {
    let box = element.getBoundingClientRect();
    let width = box.right - box.left,
        height = box.bottom - box.top;
    return { width, height };
}


export const on = ( function () {
    if ( document.addEventListener ) {
        return function ( element, event, handler ) {
            if ( element && event && handler ) {
                element.addEventListener( event, handler, false );
            }
        };
    } else {
        return function ( element, event, handler ) {
            if ( element && event && handler ) {
                element.attachEvent( 'on' + event, handler );
            }
        };
    }
} )();


export const off = ( function () {
    if ( document.removeEventListener ) {
        return function ( element, event, handler ) {
            if ( element && event ) {
                element.removeEventListener( event, handler, false );
            }
        };
    } else {
        return function ( element, event, handler ) {
            if ( element && event ) {
                element.detachEvent( 'on' + event, handler );
            }
        };
    }
} )();


export const once = function ( el, event, fn ) {
    var listener = function () {
        if ( fn ) {
            fn.apply( this, arguments );
        }
        off( el, event, listener );
    };
    on( el, event, listener );
};


export function hasClass( el, cls ) {
    if ( !el || !cls ) return false;
    if ( cls.indexOf( ' ' ) !== -1 ) throw new Error( 'className should not contain space.' );
    if ( el.classList ) {
        return el.classList.contains( cls );
    } else {
        return ( ' ' + el.className + ' ' ).indexOf( ' ' + cls + ' ' ) > -1;
    }
};


export function addClass( el, cls ) {
    if ( !el ) return;
    var curClass = el.className;
    var classes = ( cls || '' ).split( ' ' );

    for ( var i = 0, j = classes.length; i < j; i++ ) {
        var clsName = classes[ i ];
        if ( !clsName ) continue;

        if ( el.classList ) {
            el.classList.add( clsName );
        } else {
            if ( !hasClass( el, clsName ) ) {
                curClass += ' ' + clsName;
            }
        }
    }
    if ( !el.classList ) {
        el.className = curClass;
    }
};


export function removeClass( el, cls ) {
    if ( !el || !cls ) return;
    var classes = cls.split( ' ' );
    var curClass = ' ' + el.className + ' ';

    for ( var i = 0, j = classes.length; i < j; i++ ) {
        var clsName = classes[ i ];
        if ( !clsName ) continue;

        if ( el.classList ) {
            el.classList.remove( clsName );
        } else {
            if ( hasClass( el, clsName ) ) {
                curClass = curClass.replace( ' ' + clsName + ' ', ' ' );
            }
        }
    }
    if ( !el.classList ) {
        el.className = trim( curClass );
    }
};


export const getStyle = ( element, styleName ) => {
    if ( !element || !styleName ) return null;
    styleName = camelCase( styleName );
    if ( styleName === 'float' ) {
        styleName = 'cssFloat';
    }
    try {
        var computed = document.defaultView.getComputedStyle( element, '' );
        return element.style[ styleName ] || computed ? computed[ styleName ] : null;
    } catch ( e ) {
        return element.style[ styleName ];
    }
};


export function setStyle( element, styleName, value ) {
    if ( !element || !styleName ) return;

    if ( typeof styleName === 'object' ) {
        for ( var prop in styleName ) {
            if ( styleName.hasOwnProperty( prop ) ) {
                setStyle( element, prop, styleName[ prop ] );
            }
        }
    } else {
        styleName = camelCase( styleName );
        element.style[ styleName ] = value;
    }
};
